
import json

from django.db import transaction
from django.db.models import F
from django_filters.rest_framework import DjangoFilterBackend, filters
from rest_framework.views import Response
from rest_framework import mixins, viewsets, status
from rest_framework.decorators import action
from rest_framework.filters import OrderingFilter
from rest_framework.permissions import IsAuthenticated

from apps.common.account.models import Account
from apps.prize_system.prize.filters import PrizeFilter
from apps.prize_system.prize.models import PrizeCategory, PrizeRank, PrizeLevel, Prize, PrizeCheck, PrizeAuthor, \
    PrizeFile
from apps.prize_system.prize.serializers import PrizeCategorySerializer, \
    PrizeRankSerializer, PrizeLevelSerializer, AuthorUpdateSerializer, AuthorCreateSerializer, PrizeListSerializer, \
    PrizeUpdateSerializer, SecondCheckListSerializer, PrizeRetrieve, PrizeCreateSerializer, FirstCheckListSerializer

from utils.common import Pagination


class PrizeCategoryViewSet(mixins.ListModelMixin,
                           mixins.CreateModelMixin,
                           mixins.DestroyModelMixin,
                           viewsets.GenericViewSet):
    queryset = PrizeCategory.objects.all()
    pagination_class = Pagination
    serializer_class = PrizeCategorySerializer
    filter_backends = (OrderingFilter, DjangoFilterBackend)
    ordering_fields = ('id',)
    permission_classes = [IsAuthenticated]      # 需要登陆用户才能访问，开发时注释掉


class PrizeRankViewSet(mixins.ListModelMixin,
                       mixins.CreateModelMixin,
                       mixins.DestroyModelMixin,
                       viewsets.GenericViewSet):
    queryset = PrizeRank.objects.all()
    pagination_class = Pagination
    serializer_class = PrizeRankSerializer
    filter_backends = (OrderingFilter, DjangoFilterBackend)
    ordering_fields = ('id',)
    permission_classes = [IsAuthenticated]      # 需要登陆用户才能访问，开发时注释掉


class PrizeLevelViewSet(mixins.ListModelMixin,
                        mixins.CreateModelMixin,
                        mixins.DestroyModelMixin,
                        viewsets.GenericViewSet):
    queryset = PrizeLevel.objects.all()
    pagination_class = Pagination
    serializer_class = PrizeLevelSerializer
    filter_backends = (OrderingFilter, DjangoFilterBackend)
    ordering_fields = ('id',)
    permission_classes = [IsAuthenticated]      # 需要登陆用户才能访问，开发时注释掉


class PrizeViewSet(viewsets.ModelViewSet):
    queryset = Prize.objects.select_related('prize_level', 'prize_category', 'prize_rank')
    filter_backends = (DjangoFilterBackend, OrderingFilter)
    serializer_class = PrizeListSerializer
    pagination_class = Pagination
    ordering_fields = ('id',)
    filter_class = PrizeFilter

    def get_serializer_class(self):  # 动态序列化
        if self.action == 'retrieve':
            return PrizeRetrieve
        return PrizeListSerializer

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        return Response(status=status.HTTP_204_NO_CONTENT)

    def perform_destroy(self, instance):
        """ 重新删除的实现方法，删除时删除保存在本地的文件 """
        file_objs = PrizeFile.objects.filter(prize=instance)
        for i in file_objs:
            i.file.delete()
        instance.delete()

    def create(self, request, *args, **kwargs):
        author_student = request.data.get('author_student', '[]')
        author_teacher = request.data.get('author_teacher', '[]')
        files = request.data.getlist('file', [])
        if not author_student or not files:
            return Response({'message': '必须有获奖学生的信息和附件'}, status=status.HTTP_400_BAD_REQUEST)
        author_student = json.loads(author_student)
        author_teacher = json.loads(author_teacher)

        student_sum_contribution_rate = 0
        teacher_sum_contribution_rate = 0
        try:
            for author in author_student:
                student_sum_contribution_rate += int(author.get('contribution_rate', 0))
                # 如果不是外校人员，则姓名是下拉框，得到的数据是id
                if author['author_type'] != '外校学生':
                    account = Account.objects.only('id', 'realname').get(id=author['name'])
                    author['account_id'] = account.id
                    author['name'] = account.realname
                    author['faculty_code'] = account.faculty_code
                    author['faculty_title'] = account.faculty_title
                    author['job_num'] = account.username
            if author_teacher:
                for author in author_teacher:
                    teacher_sum_contribution_rate += int(author.get('contribution_rate', 0))
                    # 如果不是外校人员，则姓名是下拉框，得到的数据是id
                    if author['author_type'] != '外校老师':
                        account = Account.objects.only('id', 'realname').get(id=author['name'])
                        author['account_id'] = account.id
                        author['name'] = account.realname
                        author['faculty_code'] = account.faculty_code
                        author['faculty_title'] = account.faculty_title
                        author['job_num'] = account.username
        except Account.DoesNotExist:
            return Response({'message': '人员错误，本校不存在该人员'}, status=status.HTTP_400_BAD_REQUEST)
        if student_sum_contribution_rate != 100:
            return Response({'message': '所有获奖的学生的总贡献率和不等于100'}, status=status.HTTP_400_BAD_REQUEST)
        if author_teacher and teacher_sum_contribution_rate != 100:
            return Response({'message': '所有获奖的老师的总贡献率和不等于100'}, status=status.HTTP_400_BAD_REQUEST)
        serializer = PrizeCreateSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        try:
            with transaction.atomic():
                self.perform_create(serializer)
                prize_id = serializer.data['id']
                author_lst = author_student + author_teacher
                author_objs = [PrizeAuthor(**author, prize_id=prize_id) for author in author_lst]
                file_objs = [PrizeFile(prize_id=prize_id, file=file, file_name=file.name,
                                       file_type=file.content_type) for file in files]
                PrizeAuthor.objects.bulk_create(author_objs)
                PrizeFile.objects.bulk_create(file_objs)
        except Exception as e:
            print(e.args)
            return Response({'message': e.args}, status=status.HTTP_400_BAD_REQUEST)

        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def update(self, request, *args, **kwargs):
        """ 注意: 已经审核通过的数据不允许更新 """
        instance = self.get_object()
        author_student = request.data.get('author_student', '[]')
        author_teacher = request.data.get('author_teacher', '[]')
        if not author_student:
            return Response({'message': '必须有获奖学生的信息'}, status=status.HTTP_400_BAD_REQUEST)
        if instance.first_check_status == '通过' or instance.second_check_status == '通过':
            return Response({'message': '审核已经通过的数据不允许修改'}, status=status.HTTP_400_BAD_REQUEST)
        author_student = json.loads(author_student)
        author_teacher = json.loads(author_teacher)

        student_sum_contribution_rate = 0
        teacher_sum_contribution_rate = 0

        author_add = []  # 保存将要添加的获奖人信息
        author_update = []  # 保存将要更新的获奖人的信息
        # 获取该成果所有原获奖人，比较看哪些是修改，删除和添加的
        author_ids = PrizeAuthor.objects.filter(prize=instance).values_list('id', flat=True)
        author_delete = set(author_ids)  # 保存将要删除的作者的id
        for author in author_student:
            student_sum_contribution_rate += int(author.get('contribution_rate', 0))
            author['prize'] = instance.id
            # 如果是本校老师，1.姓名是用户的id(如果是新增或者修改本校老师，则是id) 2.正常姓名(原有的本校老师不修改姓名)
            # 不是本校老师则是正常的名字，此时要将account_id设置为None，考虑到将本校老师改为其他类型的，
            # 若不将account_id设置为None, 则该条修改后的作者信息仍关联着原作者
            if author['author_type'] != '外校学生':
                try:
                    user_id = int(author['name'])
                    account = Account.objects.only('id', 'realname').get(id=user_id)
                    author['account'] = account.id
                    author['name'] = account.realname
                    author['faculty_code'] = account.faculty_code
                    author['faculty_title'] = account.faculty_title
                    author['job_num'] = account.username
                except ValueError:
                    pass
            else:
                author['account'] = None
            # 有传id进来，则是需要修改的，没有id则是添加的
            # 从所有获奖人中去掉需要修改的，剩下的则是要删除的
            author_id = author.get('id', None)
            if author_id:
                author_delete.remove(author_id)
                author_update.append(author)
            else:
                author_add.append(author)

        if author_teacher:
            for author in author_teacher:
                teacher_sum_contribution_rate += int(author.get('contribution_rate', 0))
                author['prize'] = instance.id
                # 如果是本校老师，1.姓名是用户的id(如果是新增或者修改本校老师，则是id) 2.正常姓名(原有的本校老师不修改姓名)
                # 不是本校老师则是正常的名字，此时要将account_id设置为None，考虑到将本校老师改为其他类型的，
                # 若不将account_id设置为None, 则该条修改后的作者信息仍关联着原作者
                if author['author_type'] != '外校老师':
                    try:
                        user_id = int(author['name'])
                        account = Account.objects.only('id', 'realname').get(id=user_id)
                        author['account'] = account.id
                        author['name'] = account.realname
                        author['faculty_code'] = account.faculty_code
                        author['faculty_title'] = account.faculty_title
                        author['job_num'] = account.username
                    except ValueError:
                        pass
                else:
                    author['account'] = None
                # 有传id进来，则是需要修改的，没有id则是添加的
                # 从所有获奖人中去掉需要修改的，剩下的则是要删除的
                author_id = author.get('id', None)
                if author_id:
                    author_delete.remove(author_id)
                    author_update.append(author)
                else:
                    author_add.append(author)

        if student_sum_contribution_rate != 100:
            return Response({'message': '所有获奖的学生的总贡献率和不等于100'}, status=status.HTTP_400_BAD_REQUEST)
        if author_teacher and teacher_sum_contribution_rate != 100:
            return Response({'message': '所有获奖的老师的总贡献率和不等于100'}, status=status.HTTP_400_BAD_REQUEST)

        # 如果有要删除的获奖人，则删除
        if author_delete:
            PrizeAuthor.objects.filter(id__in=author_delete).delete()
        author_lst = author_student + author_teacher
        # 如果有id则是更新，没有则是新增
        for author in author_lst:
            author_id = author.get('id', None)
            if author_id:
                obj = PrizeAuthor.objects.get(id=author['id'])
                serializer = AuthorUpdateSerializer(obj, data=author, partial=True)
            else:
                serializer = AuthorCreateSerializer(data=author)
            serializer.is_valid(raise_exception=True)
            serializer.save()

        # 有新增的文件则增加
        files = request.data.getlist('file', [])
        file_objs = [PrizeFile(prize=instance, file=file, file_name=file.name, file_type=file.content_type)
                     for file in files]
        PrizeFile.objects.bulk_create(file_objs)

        # 有要删除的文件则删除
        delete_files = request.data.get('delete_file_id', None)
        if delete_files:
            delete_files = json.loads(delete_files)
            queryset = PrizeFile.objects.filter(id__in=delete_files)
            for i in queryset:
                # 调用文件字段的delete方法，可以删除本地保存的文件
                i.file.delete()
            queryset.delete()

        serializer = PrizeUpdateSerializer(instance, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return Response(serializer.data)

    @action(methods=['get'], detail=False, url_path='first_check_list')
    def first_check_list(self, request, *args, **kwargs):
        """ 获取一级审核待审核的数据 """
        faculty_code = request.query_params.get('faculty_code', '')
        if not faculty_code:
            return Response({'message': '必须要有学院代码！'}, status=status.HTTP_400_BAD_REQUEST)
        if faculty_code == 'view_all_second_faculty':
            queryset = Prize.objects.select_related('prize_category', 'prize_level', 'prize_rank') \
                .filter(first_check_status='待审核')
        else:
            prize_ids = PrizeAuthor.objects.filter(faculty_code=faculty_code).values_list('prize_id', flat=True)
            queryset = Prize.objects.select_related('prize_category', 'prize_level', 'prize_rank') \
                .filter(first_check_status='待审核', id__in=prize_ids)
        queryset = self.filter_queryset(queryset)

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = FirstCheckListSerializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = FirstCheckListSerializer(queryset, many=True)
        return Response(serializer.data)

    @action(methods=['get'], detail=False, url_path='second_check_list')
    def second_check_list(self, request, *args, **kwargs):
        """ 获取二级审核待审核的数据, 一级审核通过后才进行二级审核 """
        queryset = Prize.objects.select_related('prize_category', 'prize_level', 'prize_rank')\
            .filter(first_check_status='通过', second_check_status='待审核')
        queryset = self.filter_queryset(queryset)

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = SecondCheckListSerializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = SecondCheckListSerializer(queryset, many=True)
        return Response(serializer.data)

    @action(methods=['post'], detail=True, url_path='first_check')
    def first_check(self, request, pk=None):
        """ 进行一级审核 """
        check_status = request.data.get('check_status', '')
        check_opinion = request.data.get('check_opinion', '')
        if check_status not in ('通过', '退回修改'):
            return Response({'message': '缺少审核状态或者审核状态错误'}, status=status.HTTP_400_BAD_REQUEST)
        try:
            instance = Prize.objects.only('id').get(id=pk)
        except Prize.DoesNotExist:
            return Response({'message': '错误的参数'}, status=status.HTTP_400_BAD_REQUEST)

        PrizeCheck.objects.create(prize=instance, check_status=check_status, check_opinion=check_opinion,
                                  check_level=1)
        # 每次审核后将一级审核状态改为最新的审核状态
        instance.first_check_status = check_status
        instance.save()
        return Response({'message': '审核成功'}, status=status.HTTP_200_OK)

    @action(methods=['post'], detail=True, url_path='second_check')
    def second_check(self, request, pk=None):
        """ 进行二级审核 """
        check_status = request.data.get('check_status', '')
        check_opinion = request.data.get('check_opinion', '')
        if check_status not in ('通过', '退回修改'):
            return Response({'message': '缺少审核状态或者审核状态错误'}, status=status.HTTP_400_BAD_REQUEST)
        try:
            instance = Prize.objects.only('id').get(id=pk)
        except Prize.DoesNotExist:
            return Response({'message': '错误的参数'}, status=status.HTTP_400_BAD_REQUEST)

        PrizeCheck.objects.create(prize=instance, check_status=check_status, check_opinion=check_opinion,
                                  check_level=2)
        if check_status == '退回修改':
            # 二级审核退回后，流程重新走，修改后再重新一级审核二级审核这样走
            instance.first_check_status = check_status
        # 每次审核后将二级审核状态改为最新的审核状态
        instance.second_check_status = check_status
        instance.save()
        return Response({'message': '审核成功'}, status=status.HTTP_200_OK)

    @action(methods=['get'], detail=False, url_path='my_prize')
    def get_my_prize(self, request, *args, **kwargs):
        """ 获取自己的获奖(只要有参与的就算) """
        user = request.user
        # 获取自己参与的全部获奖的id
        obj_qs = PrizeAuthor.objects.filter(account=user).values_list('prize_id', flat=True)

        queryset = Prize.objects.filter(id__in=obj_qs)
        queryset = self.filter_queryset(queryset)

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = PrizeListSerializer(page, many=True, context={'account_id': user.id})
            res_data = {
                'results': serializer.data,
                'count': len(queryset),
            }
            return Response(res_data)

        serializer = PrizeListSerializer(queryset, many=True, context={'account_id': user.id})
        return Response(serializer.data)